---
id: database
title: Database
sidebar_label: Database
slug: /api/outstation/database
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

You can use the `Database` class to manipulate the measurement types and values that the outstation exposes to the master. Note that while it's called a "database", it's really just
a in-memory data structure protected by a mutex.

All database operations are executed inside a transaction protected by a mutex. Operations within a transaction are applied to the database and the
event buffers atomically. If unsolicited responses are enabled, the outstation will automatically decide if an unsolicited response
should be sent at the end of the transaction.

The database may be accessed in a transaction in two different ways:

1. When measurement values need to updated due to some external changes, the user can call `Outstation.transaction` to acquire
a locked reference to the database and make changes.

2. Callbacks on the `ControlHandler` provide a `DatabaseHandle` which also has an identical `transaction method`. Similarly, the freeze operations on
`OutstationApplication` provide this handle as well.

:::tip
Structure any common update code to operate on the `Database` type and not depend on `Outstation` or `DatabaseHandle`.
:::

## Adding Points

You must initialize the points before the outstation exposes any measurement data. While you should do this when you create the outstation, you can add points to a running outstation as well. Each measurement type has unique configuration including:

* An optional event class assignment for the point
* Default static and event variations for the type
* Type-specific dead-bands that default to zero (Binary points have no deadband)

:::caution
The default static and event variations for each point type may not do what you expect them to do. For example,
some DNP3 event variations don't carry a timestamp. This can be confusing to new users who expect to see a timestamp
value that changes as the outstation receives events.

Refer to the documentation for each variation to understand the data associated with it.
:::

When you add a point, it is assigned the following default value with `RESTART` flags:

* Binary points are set to `false`
* Numeric values are set to `0`
* Double-bit Binary points set to `Indeterminate`
* Octet Strings are set to the value of `[0x00]`

Update the value after adding the point if you don't want a connecting master to see the points with a `RESTART` flag set.

:::tip
The example code below only shows the definition of contiguous ranges of points, however, the library efficiently supports
using discontiguous ranges as well. In fact, no matter how you define the indices, the library always uses a [BTreeMap](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html)
to store static values and their configuration.
:::

<Tabs
groupId="language"
defaultValue="Rust"
values={[
{label: 'Rust', value: 'Rust'},
{label: 'C', value: 'C'},
{label: 'C++', value: 'C++'},
{label: 'Java', value: 'Java'},
{label: 'C#', value: 'C#'},
]}>
<TabItem value="Rust">

```rust
{{#include ../dnp3/examples/outstation.rs:database_init}}
```

</TabItem>
<TabItem value="C">

```c
// initialize 10 of every point type
{{#include ../ffi/bindings/c/outstation_example.c:database_init_transaction}}

// during program initialization - "outstation" already created
{{#include ../ffi/bindings/c/outstation_example.c:database_init}}
```

</TabItem>
<TabItem value="C++">

```cpp
// initialize 10 of every point type
{{#include ../ffi/bindings/c/outstation_example.cpp:database_init_transaction}}
```

</TabItem>
<TabItem value="Java">

```java
// you can use a separate method or just initialize directly in the lambda expression
{{#include ../ffi/bindings/java/examples/src/main/java/io/stepfunc/dnp3/examples/OutstationExample.java:database_init_function}}

// during program initialization - "outstation" already created
{{#include ../ffi/bindings/java/examples/src/main/java/io/stepfunc/dnp3/examples/OutstationExample.java:database_init}}
```

</TabItem>
<TabItem value="C#">

```csharp
{{#include ../ffi/bindings/dotnet/examples/outstation/Program.cs:database_init}}
```

</TabItem>
</Tabs>

## Updating Points

You can update a point value in a new transaction or in the same transaction you used to initialize it. This is useful if the outstation
has local access to values at startup, such as via a local ADC. When initializing point values, it is recommended to use the
`UpdateOptions::no_event()`.

The `Flags` value can be built by ORing values from the constants available in `Flag`. Note that not all `Flag` values are available
in every point type.

The `UpdateOptions` struct lets you precisely control how a point update is processed. Use the default constructor to:

* Update the static value
* Produce an event if the point value changes in a way that exceeds the deadband or if the flags change

:::tip
Use the UpdateOptions to ignore event creation during startup initialization if you don't want to create events for the initial values.
:::

## Getting Point Values

Some applications may wish to use the `Database` as a cache of the most recent value. Each type has a getter method to retrieve the most recently assigned value.

:::note
Since the point may not be defined, the getters can fail. If you try to retrieve a point that doesn't exist using Java and C#, an exception will be thrown.
:::

## Removing Points

Most applications don't need to remove points, but the option is there in case you want to remove points from a running outstation. There is a type-specific function for removing every point type given its index.

:::note
Removing a point stops the outstation from reporting static data for that point. However, it does NOT remove any queued events for that point from
the event buffer. Those events will remain in the event buffer until they are reported and cleared by confirmation.
:::

## Defining Device Attributes

Specific attributes from Group 0 may be defined using the database. As you can see in the examples above, this should typically be done during database initialization. Rust
uses a single method for defining attributes whereas the bindings have different methods for each type of attribute. Only attributes that are defined as writable are eligible
to receive WRITE callbacks in the [OutstationApplication](application) interface.

### Default Set

The standard predefines a number of attributes belonging to the default set (index == 0). The database will only allow you define values with the correct type for these objects. It
will also enforce that only certain variations are writable. Writable variations in the default set are:

* Variation 206 - User-assigned secondary operator name
* Variation 207 - User-assigned primary operator name
* Variation 207 - User-assigned primary operator name
* Variation 244 - User-assigned owner name
* Variation 245 - User-assigned location
* Variation 246 - User-assigned ID code/number
* Variation 247 - User-assigned device name

### Private Sets

Private sets are sets with any index other than 0. User may assign any attribute values to variations within these sets
other than the reserved variation numbers 0, 254, and 255.


